#####################################
##       PEinjector/action         ##
#####################################

# Actions ID Info:
# .----+--------------+--------------------------.
# | ID | Args         | Actions                  |
# +====+==============+==========================+
# | 0  | pkg_name     | start load pkg (for log) |
# +----+--------------+--------------------------+
# | 1  | path         | mkdir                    |
# +----+--------------+--------------------------+
# | 2  | from, to     | copy <file>              |
# +----+--------------+--------------------------+
# | 3  | from, to     | link <file>              |
# +----+--------------+--------------------------+
# | 4  | from, to     | link <path>              |
# +----+--------------+--------------------------+
# | 5  | command      | start                    |
# +----+--------------+--------------------------+
# | 6  |path,icon,name| make shortcut on Desktop |
# +----+--------------+--------------------------+
# | 7  | path         | add <path> to %PATH%     |
# +----+--------------+--------------------------+
# | 8  | regpath      | add file to reg          |
# '----+--------------+--------------------------'


import os
import config
import utils
import pickle
import log
import shutil
import subprocess
import makelnk
import regwrite


def force_copy(pkg_path: str, pkg_name: str, data_list: list, froms: str, tos: str) -> list[tuple]:
    froms = froms.replace("\\", "/")
    if len(froms) > 1 and froms[-1] == '/':
        froms = froms[:-1]
    tos = tos.replace("\\", "/")
    if len(tos) > 1 and tos[-1] == '/':
        tos = tos[:-1]
    datas = []
    data_dir = config.DATAPATH.format(DISK=utils.find_disk())+"/"+pkg_name

    data_check = [i["from"] for i in data_list]

    def search_dir(path):
        if froms+path in data_check:
            datas.append(
                (4, pkg_path+"/"+froms+path, data_dir+"/"+data_list[data_check.index(froms+path)]["to"]))
        else:
            datas.append((1, tos+path))
            for i in os.listdir(pkg_path+"/"+froms+path):
                if os.path.isfile(pkg_path+"/"+froms+path+"/"+i):
                    if froms+path+"/"+i in data_check:
                        datas.append(
                            (3, pkg_path+"/"+froms+path+"/"+i, data_dir+data_list[data_check.index(froms+path+"/"+i)]["to"]))
                    else:
                        datas.append(
                            (2, pkg_path+"/"+froms+path+"/"+i, tos+path+"/"+i))
                else:
                    search_dir(path+"/"+i)
    search_dir("")
    return datas


def copy(pkg_path: str, pkg_name: str, data_list: list, froms: str, tos: str) -> list:
    froms = froms.replace("\\", "/")
    if len(froms) > 1 and froms[-1] == '/':
        froms = froms[:-1]
    tos = tos.replace("\\", "/")
    if len(tos) > 1 and tos[-1] == '/':
        tos = tos[:-1]
    datas = []
    data_dir = config.DATAPATH.format(DISK=utils.find_disk())+"/"+pkg_name

    data_check = [i["from"] for i in data_list]

    def search_dir(path: str):  # dfs search
        if froms+path in data_check:
            datas.append(
                (4, pkg_path+"/"+froms+path, data_dir+"/"+data_list[data_check.index(froms+path)]["to"]))
        else:
            datas.append((1, tos+path))
            for i in os.listdir(pkg_path+"/"+froms+path):
                if os.path.isfile(pkg_path+"/"+froms+path+"/"+i):
                    if froms+path+"/"+i in data_check:
                        datas.append(
                            (3, pkg_path+"/"+froms+path+"/"+i, data_dir+data_list[data_check.index(froms+path+"/"+i)]["to"]))
                    else:
                        datas.append(
                            (3, pkg_path+"/"+froms+path+"/"+i, tos+path+"/"+i))
                else:
                    search_dir(path+"/"+i)
    search_dir("")
    return datas


def start(pkg_name: str, data_list: list, cmd: str) -> list:
    return [(5, cmd)]


def save_action(actions_list: list) -> None:
    tmp_filename = "PEinjector.tmp"
    log.info(f"save action list to {config.TEMP_DIR.format(
        TEMP="X:\\PEinjector")+'\\'+tmp_filename}")
    with open(config.TEMP_DIR.format(TEMP="X:\\PEinjector")+"\\"+tmp_filename, "wb") as file:
        pickle.dump(actions_list, file)
    return tmp_filename


def do_action(actions_list: list) -> tuple:
    removeinfo = {}
    actionlogs = "----- Action Log Start -----\r\n"
    thispack = "__null__"
    for i in actions_list:
        if i[0] == 0:
            actionlogs = actionlogs+f"Load [{i[1]}]\r\n"
            thispack = i[1]
            removeinfo[thispack] = []
        elif i[0] == 1:
            try:
                os.mkdir(i[1], mode=0o777)
            except Exception as exp:
                actionlogs = actionlogs + \
                    f"    mkdir \"{i[1]}\" failed: {repr(exp)}\r\n"
            else:
                removeinfo[thispack].insert(0, i)
        elif i[0] == 2:
            try:
                shutil.copyfile(i[1], i[2])
            except Exception as exp:
                actionlogs = actionlogs + \
                    f"    copy \"{i[1]}\" to " + \
                    f"\"{i[2]}\" failed: {repr(exp)}\r\n"
        elif i[0] == 3:
            try:
                os.symlink(i[1], i[2])
            except Exception as exp:
                actionlogs = actionlogs + \
                    f"    link(S) \"{i[1]}\" to " + \
                    f"\"{i[2]}\" failed: {repr(exp)}\r\n"
        elif i[0] == 4:
            try:
                assert os.system(f"mklink /J {i[1].replace(
                    '/', '\\')} {i[2].replace('/', '\\')} > nul") == 0, "mklink return not 0"
            except Exception as exp:
                actionlogs = actionlogs + \
                    f"    link(J) \"{i[1]}\" to " + \
                    f"\"{i[2]}\" failed: {repr(exp)}\r\n"
        elif i[0] == 5:
            try:
                subprocess.Popen(
                    "start "+i[1], shell=True)
            except Exception as exp:
                actionlogs = actionlogs + \
                    f"    start \"{i[1]}\" failed: {repr(exp)}\r\n"
        elif i[0] == 6:
            try:
                makelnk.makelnk(i[3],
                                i[1].replace("\\", "/"), i[2].replace("\\", "/"))
            except:
                actionlogs = actionlogs + \
                    f"    make shortcut \"{i[1]}\" failed: {repr(exp)}\r\n"
        elif i[0] == 7:
            try:
                regwrite.add_path(i[1])
            except:
                actionlogs = actionlogs + \
                    f"    add path \"{i[1]}\" failed: {repr(exp)}\r\n"
        elif i[0] == 8:
            try:
                regwrite.add_reg(i[1])
            except:
                actionlogs = actionlogs + \
                    f"    add reg \"{i[1]}\" failed: {repr(exp)}\r\n"
    return (actionlogs, removeinfo)
